package com.jiang.storage1;

import com.jiang.operator.RSAUtils;
import com.jiang.operator.StringUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 暂且充当各个边缘服务器
 */
public class Node {
    private String id;//节点id
    private double disk;//存储量
    private double use_disk;//该节点已经被利用的存储资源
    private List<String> data;//该节点保存的数据项
    private double x;//横坐标
    private double y;//纵坐标
    private int tokens;//令牌数
    private Map<String, String> account;//节点也需要拥有自己的账户。公私钥

    public Node() {
        this.data = new ArrayList<String>();
        /**
        //随机生成有的存储资源
        this.disk = Math.random()*5100+20;//保底的资源的20
        //随机生成已有的存储资源，但有范围，设置容器资源之内，单位为MB
        this.use_disk = Math.random()*(this.disk/2)+1;//保底使用的资源是5，最高15
        this.x = Math.random()*10+1;//1-11
        this.y = Math.random()*10+1;//位置随机
         */
        this.account = RSAUtils.createKeys(1024);
        this.tokens = (int)(Math.random())*10+1; //令牌数量设置为1-10
    }

    public int getTokens() {
        return tokens;
    }

    public void setTokens(int tokens) {
        this.tokens = tokens;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public List<String> getData() {
        return data;
    }

    public void setData(String data) {
        this.data.add(data);
    }

    public double getDisk() {
        return disk;
    }

    public void setDisk(double disk) {
        this.disk = disk;
    }

    public double getUse_disk() {
        return use_disk;
    }

    public void setUse_disk(double use_disk) {
        this.use_disk += use_disk;
    }

    public Map<String, String> getAccount() {
        return account;
    }

    public void setAccount(Map<String, String> account) {
        this.account = account;
    }

    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", disk=" + disk +
                ", use_disk=" + use_disk +
                ", data=" + data +
                ", x=" + x +
                ", y=" + y +
                '}';
    }

    /**
     * 计算存储成本，需要进行修改
     * 之前是根据使用存储量/剩余存储量之比来确定存储成本，剩余量越多，成本越低
     * 现在修改为，如果使用量为0时，存储成本为0，显然是最低，如果不为0
     * 则按照这个计算，数据量/剩余量
     * @return
     */
    public double getFdc(double dataSize){
        //这个就是si
        if(use_disk == 0){
            return 0;
        }
        return (double) dataSize/(disk - use_disk);
    }

    public double getUE(String location){
        //给了上传数据的用户设备的位置
        //先将坐标定为一个坐标
        //一般无线信号工作频率在2.4GHz,UEik
        double workFrequency = 2.4;

        String[] parts = location.split("/");
        String[] dParts = parts[1].split(",");
        double dX = Double.parseDouble(dParts[0]);
        double dY = Double.parseDouble(dParts[1]);
        //先设置一个50的范围游荡
        return 20 * Math.log10(distance(dX, dY) + Math.random()*50)
                + 20 * Math.log10(workFrequency);
    }

    public double getRdc(Node node){
        //这里设置链路质量，尽量让这个成本小，显然质量越不好，成本越高，这里用
        //链路质量越不好，这个值越大，这里设置一个固定值
        //aij
        if(id == node.getId()){
            return 0;
        }else {
            return distance(node) * 0.3;
        }
    }

    public double distance(Node node){
        return Math.sqrt((node.getX()-x)*(node.getX()-x)+(node.getY()-y)*(node.getY()-y));
    }

    public double distance(double loX, double loY){
        return Math.sqrt((loX-x)*(loX-x)+(loY-y)*(loY-y));
    }

    /**
     * 这个作为目标函数
     * @param time
     * @return
     */
    public double getGoal(long time){
        //这里先以25MB为单位，作为标准
        /**
         * return tokens * ((double)use_disk/25) * (System.currentTimeMillis() - time);
         */
        return tokens * ((double)use_disk/25) * 20000;
    }

    /**
     * 该函数计算命中率，命中目标值范围内
     * @param m 代表模数
     * @return
     */
    public int getHit(int m, long time){
        System.out.println(getGoal(time));
        int nonce = 0;
        String temp;
        temp = StringUtil.applySha256(account.get("publicKey"));
        while(convert(temp.substring(0,7)) % m > getGoal(time)){
            nonce++;
            temp = StringUtil.applySha256(nonce+account.get("publicKey"));
            System.out.println("========这是第"+nonce+"次====="+convert(temp.substring(0,7)) % m+"====");
        }
        return convert(temp.substring(0,7)) % m;
    }

    public int convert(String content){
        int number = 0;
        String[] HighLetter = {"a", "b", "c", "d", "e", "f"};
        Map<String,Integer> map = new HashMap<>();
        for(int i = 0;i <= 9;i++){
            map.put(i+"",i);
        }
        for(int j= 10;j<HighLetter.length+10;j++){
            map.put(HighLetter[j-10],j);
        }
        String[]str = new String[content.length()];
        for(int i = 0; i < str.length; i++){
            str[i] = content.substring(i,i+1);
        }
        for(int i = 0; i < str.length; i++){
            number += map.get(str[i])*Math.pow(16,str.length-1-i);
        }
        return number;
    }
}
